package vertx;

import io.vertx.config.ConfigRetriever;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.mysqlclient.MySQLConnectOptions;
import io.vertx.mysqlclient.MySQLPool;
import io.vertx.sqlclient.*;

import java.util.ArrayList;

public class FuturePromiseVerticle extends AbstractVerticle {

  // 第一步 声明router
  Router router;

  // 第一步 配置连接参数
  MySQLConnectOptions connectOptions;

  // 第二步 配置连接池 Pool options
  PoolOptions poolOptions = new PoolOptions()
    .setMaxSize(5);

  // 第三步 Create the client pool
  MySQLPool client ;

  @Override
  public void start(Future<Void> startFuture) throws Exception {

    // 第一步 加入这行代码
    ConfigRetriever retriever = ConfigRetriever.create(vertx);

    retriever.getConfig(ar -> {
      if (ar.failed()) {
        // Failed to retrieve the configuration
      } else {
        JsonObject config = ar.result();
        // 第二步 把start方法中原来的代码放到这下面
        connectOptions= new MySQLConnectOptions()
          .setPort(Integer.parseInt(config.getValue("port").toString()))
          .setHost(config.getString("host"))
          .setDatabase(config.getString("database"))
          .setUser(config.getString("user"))
          .setPassword(config.getString("password"));

        client = MySQLPool.pool(vertx, connectOptions, poolOptions);

        // 第二步 初始化Router
        router = Router.router(vertx);

        // 第四步 配置Router解析url
        router.route("/").handler(req -> {
          req.response()
            .putHeader("content-type", "text/plain")
            .end("Hello from Vert.x!");
        });

        // 第四步 配置Router解析url
        router.route("/test/list").handler(req -> {

          Integer page;
          var temp = req.request().getParam("page");
          if (temp==null){
            page = 1;
          }else {
            page = Integer.valueOf(temp);
          }

          var offset = (page-1)*10;

          // Get a connection from the pool
          // 第一步 获取数据库连接
          this.getCon()
            .compose(con->this.getRows(con, offset))// 第二步，用获取到的连接查询数据库
//            .compose(con->this.getRows(con, offset))// 第二步，用获取到的连接查询数据库
//            .compose(con->this.getRows(con, offset))// 第二步，用获取到的连接查询数据库
//            .compose(con->this.getRows(con, offset))// 第二步，用获取到的连接查询数据库
//            .compose(con->this.getRows(con, offset))// 第二步，用获取到的连接查询数据库
            .onSuccess(rows -> {
              // 第三步 加工查询出来的数据，并返回给客户端
              var list = new ArrayList<JsonObject>();
              rows.forEach(item->{
                var json = new JsonObject();
                json.put("id", item.getValue("id"));
                json.put("name", item.getValue("name"));
                list.add(json);
              });
              req.response()
                .putHeader("content-type", "application/json")
                .end(list.toString());
            });

        });


        // 第三步 将Router与vertx HttpServer 绑定
        vertx.createHttpServer().requestHandler(router).listen(8888, http -> {
          if (http.succeeded()) {
            startFuture.complete();
            System.out.println("HTTP server started on port 8888");
          } else {
            startFuture.fail(http.cause());
          }
        });
      }
    });

  }


  // 第一步 获取数据库连接
  private Future<SqlConnection> getCon(){
    // 这一点非常关键，这个写法是固定写法
    Promise<SqlConnection> promise = Promise.promise();
    client.getConnection(ar1 -> {
      if (ar1.succeeded()) {
        System.out.println("Connected");
        // Obtain our connection
        SqlConnection conn = ar1.result();

        // 这一点非常关键，这个写法是固定写法
        promise.complete(conn);
      } else {
        // 这一点非常关键，这个写法是固定写法
        promise.fail(ar1.cause());
      }
    });

    // 这一点非常关键，这个写法是固定写法
    return promise.future();

  }

  // 第二步，用获取到的连接查询数据库
  private Future<RowSet<Row>> getRows(SqlConnection conn, Integer offset){
    // 这一点非常关键，这个写法是固定写法
    Promise<RowSet<Row>> promise = Promise.promise();
    conn
      .preparedQuery("SELECT id, name FROM test_find limit 10 offset ?")
      .execute(Tuple.of(offset), ar2 -> {
        // Release the connection to the pool
        conn.close();
        if (ar2.succeeded()) {
          // 这一点非常关键，这个写法是固定写法
          promise.complete(ar2.result());
        } else {
          // 这一点非常关键，这个写法是固定写法
          promise.fail(ar2.cause());
        }
      });
    // 这一点非常关键，这个写法是固定写法
    return promise.future();
  }

}
